package com.ruicar.afs.cloud.bizcommon.print.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruicar.afs.cloud.bizcommon.cfca.dto.CfCaSignatureDto;
import com.ruicar.afs.cloud.bizcommon.cfca.service.CfCaSignatureService;
import com.ruicar.afs.cloud.bizcommon.dto.print.PrintDto;
import com.ruicar.afs.cloud.bizcommon.dto.print.TemplateDto;
import com.ruicar.afs.cloud.bizcommon.enums.TemplatePrintType;
import com.ruicar.afs.cloud.bizcommon.print.common.TemplateJsonFmt;
import com.ruicar.afs.cloud.bizcommon.print.common.TemplatePringConstants;
import com.ruicar.afs.cloud.bizcommon.print.entity.ComPrintFormFieldMapping;
import com.ruicar.afs.cloud.bizcommon.print.entity.ComPrintFormManage;
import com.ruicar.afs.cloud.bizcommon.print.entity.ComPrintFormSealMapping;
import com.ruicar.afs.cloud.bizcommon.print.entity.ComSealBaseInfo;
import com.ruicar.afs.cloud.bizcommon.print.enums.ServiceClientTypeEnum;
import com.ruicar.afs.cloud.bizcommon.print.mapper.ComPrintFormManageMapper;
import com.ruicar.afs.cloud.bizcommon.print.service.ComPrintFormFieldMappingService;
import com.ruicar.afs.cloud.bizcommon.print.service.ComPrintFormManageService;
import com.ruicar.afs.cloud.bizcommon.print.service.ComPrintFormSealMappingService;
import com.ruicar.afs.cloud.bizcommon.print.service.ComSealBaseInfoService;
import com.ruicar.afs.cloud.bizcommon.util.TemplatePrintUtil;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.query.QueryCondition;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.common.rules.RuleHelper;
import com.ruicar.afs.cloud.common.rules.constants.RuleRunEnum;
import com.ruicar.afs.cloud.common.rules.dto.RuleResult;
import com.ruicar.afs.cloud.common.rules.dto.RuleRunResult;
import com.ruicar.afs.cloud.image.config.FileProperties;
import com.ruicar.afs.cloud.image.entity.ComAttachmentFile;
import com.ruicar.afs.cloud.image.enums.IsDeleteEnum;
import com.ruicar.afs.cloud.image.enums.SynchronizationStateEnum;
import com.ruicar.afs.cloud.image.service.ComAttachmentFileService;
import com.ruicar.afs.cloud.image.vo.UploadInputVo;
import com.ruicar.afs.cloud.parameter.commom.enums.WhetherEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 打印模板管理表服务
 *
 * @author phong
 * @version 1.0
 * @created 2020/6/8 11:40
 */
@Service
@AllArgsConstructor
@Slf4j
public class ComPrintFormManageServiceImpl extends ServiceImpl<ComPrintFormManageMapper, ComPrintFormManage> implements ComPrintFormManageService {

    private ComPrintFormFieldMappingService comPrintFormFieldMappingService;
    private ComAttachmentFileService comAttachmentFileService;
    private FileProperties fileProperties;
    private CfCaSignatureService cfCaSignatureService;
    private ComPrintFormSealMappingService comPrintFormSealMappingService;
    private ComSealBaseInfoService comSealBaseInfoService;

    /**
     * 保存模板数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveTemplate(ComPrintFormManage comPrintFormManage) {
        // 编号+版本号需唯一
        testKey(comPrintFormManage);
        // 新增模板编辑状态为失效
        comPrintFormManage.setIsEnable(TemplatePringConstants.NO);
        comPrintFormManage.setSynchronizationState(SynchronizationStateEnum.CREATE.getCode());
        // 数据保存
        this.baseMapper.insert(comPrintFormManage);
        return Boolean.TRUE;
    }

    /**
     * 删除模板
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delTemplate(String id) {
        this.baseMapper.deleteById(Long.valueOf(id));
        return Boolean.TRUE;
    }

    /**
     * 修改模板
     * @param vo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean modifyTemplate(ComPrintFormManage vo) {
        // 新增模板编辑状态为失效
        vo.setIsEnable(TemplatePringConstants.NO);
        this.baseMapper.updateById(vo);
        return Boolean.TRUE;
    }

    /**
     * 查询
     * @param queryCondition
     * @return
     */
    @Override
    public IResponse query(QueryCondition<TemplateDto> queryCondition) {

        Map<SFunction<ComPrintFormManage, ?>, Object> params = MapUtil.newHashMap();
        if (queryCondition.getCondition() != null) {
            params.put(ComPrintFormManage::getClassNo, queryCondition.getCondition().getClassNo());
            params.put(ComPrintFormManage::getId, queryCondition.getCondition().getPrintFormId());
        }

        Page<ComPrintFormManage> page = this.baseMapper.selectPage(
                new Page<ComPrintFormManage>(queryCondition.getPageNumber(), queryCondition.getPageSize()),
                Wrappers.<ComPrintFormManage>lambdaQuery().allEq(params, false));

        return IResponse.success(page);

    }

    private void testKey(ComPrintFormManage comPrintFormManage) {
        long count = this.baseMapper.selectCount(Wrappers.<ComPrintFormManage>lambdaQuery()
                .eq(ComPrintFormManage::getPrintFormId, comPrintFormManage.getPrintFormId())
                .eq(ComPrintFormManage::getVersionId, comPrintFormManage.getVersionId()));
        Assert.isTrue(count < 1,
                "编号[" + comPrintFormManage.getPrintFormId() + "],版本[" + comPrintFormManage.getVersionId() + "]重复");
    }

    /**
     * 模板预览
     *
     * @param
     * @return
     */
    public String preview(String id) {
        ComPrintFormManage template = this.getById(id);
        List<ComPrintFormFieldMapping> mappings = comPrintFormFieldMappingService.listForPrintFormId(template.getPrintFormId());
        JSONObject jo = new JSONObject();
        mappings.forEach(item -> {
            if (item.getMappingFieldId().indexOf(StrUtil.C_DOT) > 0) {
                String[] mapping = item.getMappingFieldId().split(StrUtil.BACKSLASH + StrUtil.DOT);
                JSONArray ja = null;
                if (jo.containsKey(mapping[0])) {
                    ja = jo.getJSONArray(mapping[0]);
                } else {
                    ja = new JSONArray();
                }
                ja.add(new JSONObject().put(mapping[1], item.getMappingFieldName()));
                jo.put(mapping[0], ja);
            } else {
                jo.put(item.getMappingFieldId(), item.getMappingFieldName());
            }
        });
        String fileName = template.getPrintFormName() + StrUtil.UNDERLINE + template.getPrintFormId() + StrUtil.DOT + TemplatePrintType.PDF;
        String outPath = fileProperties.getTempDir() + File.separator + fileName;
        // 获取模板
        byte[] fileByte = getTemplate(template);
        PrintDto dto = new PrintDto();
        dto.setIn(IoUtil.toStream(fileByte));
        dto.setOutPath(outPath);
        dto.setJson(JSON.toJSONString(jo));
        TemplatePrintUtil.print(dto);
        return outPath;
    }

    /**
     * 单个模板打印
     *  @param originJson 原数据
     * @param id         模板ID
     */
    public ComAttachmentFile print(JSONObject originJson, String id, String busiNo, String serviceClientType) {

        // 默认为PC端
        serviceClientType = serviceClientType!=null ? serviceClientType : AfsEnumUtil.key(ServiceClientTypeEnum.PC);
        Assert.isTrue(StrUtil.isNotBlank(id), "当前参数获取不到模板，请确认是否完善模板规则配置!");
        // 1-通过大类、小类获取模板文件
        ComPrintFormManage template = this.getById(Long.valueOf(id));
        // 2-获取远端模板
        ComAttachmentFile attachmentFile = comAttachmentFileService.getNewAttachmentFile(template.getAttachmentSubClass(), Convert.toStr(template.getId(), StrUtil.EMPTY), Convert.toStr(template.getId(), StrUtil.EMPTY));
        if(WhetherEnum.YES.getIndex().equals(attachmentFile.getIsElectronic())){
            return null;
        }
        byte[] fileByte = comAttachmentFileService.downloadAttachmentFile(attachmentFile);
        // 3-临时文件
        String fileName = template.getPrintFormName() + StrUtil.UNDERLINE + busiNo + StrUtil.DOT + TemplatePrintType.PDF;
        String outPath = fileProperties.getTempDir() + File.separator + fileName;
        File outFile = FileUtil.touch(outPath);
        // 4-组装打印参数-通过模板ID拿映射规则
        List<ComPrintFormFieldMapping> mappings = comPrintFormFieldMappingService.list(Wrappers.<ComPrintFormFieldMapping>lambdaQuery().eq(ComPrintFormFieldMapping::getTemplateId,id));
        // 5-合成数据
        String json = TemplateJsonFmt.fmtTemplateJson(originJson, mappings);
        PrintDto dto = new PrintDto();
        dto.setIn(IoUtil.toStream(fileByte));
        dto.setOutPath(outPath);
        dto.setJson(json);
        // 6-打印输出
        TemplatePrintUtil.print(dto);
        // add by sijun.yu 2020-8-12 电子签章 fangchenliang 从数据库获取签章位置
        if(AfsEnumUtil.key(ServiceClientTypeEnum.PC).equals(serviceClientType)){
            this.generateContractTempleSeal(busiNo, id, outFile);
        }
        // 7-上传
        UploadInputVo vo = new UploadInputVo();
        vo.setBusiNo(busiNo);
        vo.setBelongNo(template.getAttachmentSubClass());
        vo.setAttachmentName(template.getPrintFormName());
        vo.setAttachmentId(id);
        vo.setFileName(fileName);
        vo.setFileType(TemplatePrintType.PDF.name());
        vo.setFileSource("com_print_form_manage");
        vo.setArchiveClass(attachmentFile.getArchiveClass());
        ComAttachmentFile comAttachmentFile = comAttachmentFileService.storeFileToOss(outFile, vo);
        // 删除临时文件
        FileUtil.del(outFile);
        return comAttachmentFile;
    }

    /**
     * 通过规则进行模板打印 - 批量文件
     *
     * @param originJson
     * @param ruleJson
     * @param busiNo
     * @param groupId
     * @return
     */
    public List<ComAttachmentFile> batchPrint(JSONObject originJson, JSONObject ruleJson, String busiNo, String groupId, String serviceClientType) {

        Assert.isTrue(originJson != null, "模板打印参数为空");
        List<ComAttachmentFile> fileList= new ArrayList<>();
        // 如果不制定模板ID，则从规则中获取
        List<RuleResult> list = queryIdByGroupId(ruleJson, groupId);
        // 模板打印
        list.forEach(result -> {
            // 只取匹配到的模板且取到模板ID的才打印
            if (!Convert.toStr(result.getResult(), StrUtil.EMPTY).equals(StrUtil.EMPTY)) {
                ComAttachmentFile file = print(originJson, result.getResult().toString(), busiNo, serviceClientType);
                if(file != null){
                    fileList.add(file);
                }
            }
        });
        return fileList;
    }

    /**
     * 通过规则进行模板打印 - 单个文件
     *
     * @param originJson
     * @param ruleJson
     * @param ruleNo
     * @param busiNo
     * @return
     */
    @Override
    public String print(JSONObject originJson, JSONObject ruleJson, String busiNo, String ruleNo) {

        Assert.isTrue(originJson != null, "模板打印参数为空");
        // 如果不制定模板ID，则从规则中获取
        List<RuleResult> list = queryIdByRule(ruleJson, ruleNo);
        // 模板打印
        list.forEach(result -> {
            // 只取匹配到的模板且取到模板ID的才打印
            if (!Convert.toStr(result.getResult(), StrUtil.EMPTY).equals(StrUtil.EMPTY)) {
                print(originJson, result.getResult().toString(), busiNo, AfsEnumUtil.key(ServiceClientTypeEnum.PC));
            }
        });
        return null;
    }

    /**
     * 生成合同模板盖章
     * @param busiNo
     * @param templateId
     * @param outFile
     * @return
     */
    public File generateContractTempleSeal(String busiNo, String templateId, File outFile){

        List<ComPrintFormSealMapping> sealMappings = comPrintFormSealMappingService.getPrintFormSealMappingList(templateId);
        if(!CollectionUtils.isEmpty(sealMappings)){
            for(ComPrintFormSealMapping sealMapping:sealMappings){
                ComSealBaseInfo comSealBaseInfo = comSealBaseInfoService.getOne(Wrappers.<ComSealBaseInfo>lambdaQuery().eq(ComSealBaseInfo::getSealNo,sealMapping.getSealNo()));
                CfCaSignatureDto signDto = new CfCaSignatureDto();
                BeanUtils.copyProperties(comSealBaseInfo,signDto);
                signDto.setLocationType(sealMapping.getLocationType());
                signDto.setKeyword(sealMapping.getKeyword());
                signDto.setCoordinateX(sealMapping.getCoordinateX());
                signDto.setCoordinateY(sealMapping.getCoordinateY());
                signDto.setApplyNo(busiNo);
                outFile = cfCaSignatureService.signCfCaSealCompanySeal(signDto,outFile);
                Assert.isTrue(outFile!=null,signDto.getTemplateFormId() + "输出文件不存在");
            }
        }
        return outFile;
    }

    /**
     * 生成盖章文件
     * @param file
     * @return
     */
    public ComAttachmentFile generateSealFile(ComAttachmentFile file){

        // 1-获取远端文件流
        byte[] fileByte = comAttachmentFileService.downloadAttachmentFile(file);
        String outPath = fileProperties.getTempDir() + File.separator + file.getFileName();
        File outFile = FileUtil.writeBytes(fileByte, outPath);
        outFile = this.generateContractTempleSeal(file.getBusiNo(), file.getAttachmentCode(), outFile);

        // 2-上传
        UploadInputVo vo = new UploadInputVo();
        vo.setBusiNo(file.getBusiNo());
        vo.setBelongNo(file.getBelongNo());
        vo.setAttachmentName(file.getAttachmentName());
        vo.setAttachmentId(file.getAttachmentCode());
        vo.setFileName(file.getFileName());
        vo.setFileType(TemplatePrintType.PDF.name());
        vo.setFileSource("com_print_form_manage");
        vo.setIsDelete(IsDeleteEnum.NO.getCode());
        vo.setArchiveClass(file.getArchiveClass());
        ComAttachmentFile comAttachmentFile = comAttachmentFileService.storeFileToOss(outFile, vo);
        // 3-删除临时文件
        FileUtil.del(outFile);
        return comAttachmentFile;
    }

    /**
     * 通过规则组和规则获取模板编号
     */
    @Override
    public List<RuleResult> queryIdByRule(JSONObject runParams) {
        // 匹配到模板就返回结果
        RuleRunResult result = RuleHelper.runRule(runParams, TemplatePringConstants.TEMPLATE_GROUP_NO, true, RuleRunEnum.SERIAL);
        if (result.getHit()) {
            return result.getResults();
        } else {
            return CollUtil.newArrayList();
        }
    }

    /**
     * 通过规则组和规则获取模板编号
     */
    public List<RuleResult> queryIdByGroupId(JSONObject runParams, String groupId) {

        // 匹配到模板就返回结果
        RuleRunResult result = RuleHelper.runRule(runParams, groupId, false, RuleRunEnum.SERIAL);
        if (result.getHit()) {
            return result.getResults();
        } else {
            return CollUtil.newArrayList();
        }
    }

    /**
     * 通过规则获取模板编号
     */
    @Override
    public List<RuleResult> queryIdByRule(JSONObject runParams, String ruleNo) {

        // 匹配到模板就返回结果
        RuleRunResult result = RuleHelper.runRule(runParams, ruleNo);
        if (result.getHit()) {
            return result.getResults();
        } else {
            return CollUtil.newArrayList();
        }
    }

    /**
     * 通过模板数据得到远端OSS上的模板文件
     *
     * @param template
     * @return
     */
    private byte[] getTemplate(ComPrintFormManage template) {

        UploadInputVo vo = new UploadInputVo();
        vo.setAttachmentId(template.getAttachmentSubClass());
        vo.setBusiNo(Convert.toStr(template.getId(), StrUtil.EMPTY));
        vo.setBelongNo(Convert.toStr(template.getId(), StrUtil.EMPTY));
        byte[] byteFile = comAttachmentFileService.getComAttachmentFile(vo);
        Assert.isTrue(byteFile != null, "获取模板文件失败，请检查文件服务网路是否正常");
        return byteFile;
    }

    /**
     * 当个模板生成-测试类
     * @param originJson
     * @param filePath
     * @param fileName
     */
    public void testPrint(JSONObject originJson,String filePath,String fileName){

        // 获取文件流
        byte[] fileByte = FileUtil.readBytes(filePath);
        // 临时文件
        String outPath = fileProperties.getTempDir() + File.separator + fileName;
        File outFile = FileUtil.touch(outPath);
        // 打印输出
        PrintDto dto = new PrintDto();
        dto.setIn(IoUtil.toStream(fileByte));
        dto.setOutPath(outPath);
        dto.setJson(originJson.toString());
        TemplatePrintUtil.print(dto);
        // 电子签章
        CfCaSignatureDto signDto = new CfCaSignatureDto();
        signDto.setCustName("天津长城滨银汽车金融有限公司");
        signDto.setDetailAddress("合同专用");
        byte[] bytes = cfCaSignatureService.getCfCaSealCompanySign(signDto,outFile);
        if(bytes != null){
            outFile = FileUtil.writeBytes(bytes,outPath);
        }
        log.info("合同模板是否存在：" + FileUtil.exist(outFile));
    }

    /**
     * 通过uniqueCode获取模板
     * @param uniqueCode
     * @return
     */
    public ComPrintFormManage getPrintFormManageByUniqueCode(String uniqueCode){

        return this.baseMapper.getPrintFormManageByUniqueCode(uniqueCode);
    }


}
